#include "DataHolderGarbageCollector.h"
#include <iostream>
#include <cassert>
#include "DataHolder.h"
#include "Memory.h"

using namespace std;

DataHolderGarbageCollector* DataHolderGarbageCollector::s_instance;

DataHolderGarbageCollector::DataHolderGarbageCollector() {
	s_instance = NULL;
}

DataHolderGarbageCollector* DataHolderGarbageCollector::getInstance() {

	if (s_instance == NULL) {
		s_instance = new DataHolderGarbageCollector();
	}

	return s_instance;
}

void DataHolderGarbageCollector::addDataHolder(DataHolder* dataHolder) {
	assert(dataHolder);
	
	for (DataHolders::iterator i = m_dataHolders.begin(); i != m_dataHolders.end(); ++i) {
		DataHolder* d = (*i);
		assert(dataHolder != d);
	}
	
	m_dataHolders.push_back(dataHolder);	
}

void DataHolderGarbageCollector::deleteAll() {
	
	for (DataHolders::iterator i = m_dataHolders.begin(); i != m_dataHolders.end(); ++i) {
		DataHolder* d = (*i);
		delete d;
	}
	
	m_dataHolders.clear();
}

void DataHolderGarbageCollector::collectGarbage() {

	// 1. Set all flags to false
	for (DataHolders::iterator i = m_dataHolders.begin(); i != m_dataHolders.end(); ++i) {
		DataHolder* d = (*i);
		d->setReferenced(false);
	}
	
	// 2. Let all referencers set the flags in their child DataHolders 
	for (Referencers::iterator i = m_referencers.begin(); i != m_referencers.end(); ++i) {	
		Referencer* r = (*i);
		r->setDataHoldersToReferenced();
	}
	
	// 3. Delete all DataHolders that still have a flag set to false
	for (DataHolders::iterator i = m_dataHolders.begin(); i != m_dataHolders.end(); ) {
		if (!(*i)->isReferenced()) {
			delete (*i);
			m_dataHolders.erase(i);
		} else {
			++i;
		}
	}	
}

void DataHolderGarbageCollector::addReferencer(Referencer* referencer) {
	assert(referencer);
	
	for (Referencers::iterator i = m_referencers.begin(); i != m_referencers.end(); ++i) {	
		Referencer* r = (*i);
		assert(r != referencer);
	}
	
	m_referencers.push_back(referencer);
}

void DataHolderGarbageCollector::removeReferencer(Referencer* referencer) {
	assert(referencer);
	
	for (Referencers::iterator i = m_referencers.begin(); i != m_referencers.end(); ++i) {	
		Referencer* r = (*i);
		if (r == referencer) {
			m_referencers.erase(i);
			return;
		}
	}
	
	assert(false);
}






